package case3

import "fmt"

/** 接口示例3

1. 空接口 示例
2. 类型断言 示例
3. 类型选择 示例
4. 类型选择和接口相比较 示例
5. 接口的零值 nil
*/

// 空接口 示例
func case1() {

	str1 := "hello world!"
	desc1(str1)

	age1 := 34
	desc1(age1)
}

// 类型断言 示例
func case2() {
	var s interface{} = 56
	desc2(s)

	// 注意：断言接口中i.(int) 这里必须是int类型，不能是其他数据类型；
	//var s2 interface{} = "hello world!"
	//desc2(s2)
}

// 类型选择 示例
func case3() {
	var age1 int = 45
	findType1(age1)

	var str1 string = "hello world!"
	findType1(str1)

	findType1(true)

	var age2 uint = 34
	findType1(age2)

	var price1 float32 = 34.2
	findType1(price1)

	var price2 float64 = 34.5
	findType1(price2)
}

// 类型选择和接口相比较 示例
func case4() {
	findType2("lili")

	p1 := person{"zhangsan", 34}
	findType2(p1)
}

// 接口的零值 nil
func case5() {

	var d8 desc8
	if d8 == nil {
		fmt.Println("接口是空 ", d8)
	}
}

func Test() {

	// 空接口
	case1()

	// 类型断言
	case2()

	// 类型选择
	case3()

	// 类型选择和接口相比较
	case4()

	// 接口的零值 nil
	case5()
}

// 空接口：没有包含方法的接口称为空接口。空接口表示为 interface{}。由于空接口没有方法，因此所有类型都实现了空接口。
func desc1(i interface{}) {
	fmt.Printf("参数类型：%T, 参数值：%v   \n", i, i)
}

// 类型断言用于提取接口的底层值，在语法i.(T)中，接口i的具体类型是T，该语法用于获得接口的底层值。
func desc2(i interface{}) {
	s := i.(int)
	fmt.Println("断言使用i.(T) 获取接口底层值:", s)
}

// 类型选择
// 类型选择用于将接口的具体类型与很多 case 语句所指定的类型进行比较。它与一般的 switch 语句类似。唯一的区别在于类型选择指定的是类型，而一般的 switch 指定的是值。
// 类型选择的语法类似于类型断言。类型断言的语法是i.(T)，而对于类型选择，类型T由关键字type代替。下面看看程序是如何工作的。
func findType1(i interface{}) {
	switch i.(type) {
	case int:
		fmt.Println("类型选择，传入参数是数值，", i.(int), i)
	case string:
		fmt.Println("类型选择，传入参数是字符串，", i.(string), i)
	case bool:
		fmt.Println("类型选择，传入参数是布尔，", i.(bool), i)
	case float32:
		fmt.Println("类型选择，传入参数是浮点32，", i.(float32), i)
	case float64:
		fmt.Println("类型选择，传入参数是浮点64，", i.(float64), i)
	case uint:
		fmt.Println("类型选择，传入参数是无符号整型，", i.(uint), i)
	default:
		fmt.Printf("类型选择，default 传入参数类型是%T， 参数值%v  \n", i, i)
	}
}

// 类型选择和接口相比较
// 如果一个类型实现了接口，那么该类型与其实现的接口就可以互相比较。

type describerOne interface {
	desc()
}

type person struct {
	name string
	age  int
}

// person 结构体 实现接口
func (p person) desc() {
	fmt.Println("person 结构体参数：", p)
}

func findType2(i interface{}) {
	switch v := i.(type) {
	case describerOne:
		v.desc()
	default:
		fmt.Println("找不到这类型。。。")
	}
}

// 接口的零值 nil
type desc8 interface {
	desc()
}
